package cn.angleline.cloudhub.easbi

import au.com.console.jpaspecificationdsl.`in`
import au.com.console.jpaspecificationdsl.and
import au.com.console.jpaspecificationdsl.between
import au.com.console.jpaspecificationdsl.equal
import cn.angleline.cloudhub.easbi.eas.entity.*
import cn.angleline.cloudhub.easbi.util.EncryptUtils
import cn.angleline.cloudhub.easbi.yzj.entity.FundSummary
import cn.angleline.cloudhub.easbi.yzj.entity.FundType
import cn.angleline.cloudhub.easbi.yzj.entity.LoanEntity
import org.nield.kotlinstatistics.sumBy
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.beans.factory.annotation.Value
import org.springframework.data.domain.PageRequest
import org.springframework.stereotype.Service
import java.math.RoundingMode
import java.sql.Timestamp
import java.text.SimpleDateFormat
import java.time.Duration
import java.time.format.DateTimeFormatter
import java.util.*
import kotlin.collections.ArrayList

/**
 * 报表秀秀
 */
@Service
class PaymentBillService {

    //付款单
    @Autowired
    private lateinit var tCasPaymentBillRepo: TCasPaymentBillRepo
    //付款单分录
    @Autowired
    private lateinit var tCasPaymentBillEntryRepo: TCasPaymentBillEntryRepo
    //费用类型
    @Autowired
    private lateinit var tBcExpenseTypeRepo: TBcExpenseTypeRepo

    //收款单
    @Autowired
    private lateinit var tCasReceivingBillRepo: TCasReceivingBillRepo

    //收款类型
    @Autowired
    private lateinit var tCasReceivingBillTypeRepo: TCasReceivingBillTypeRepo

    //借款单
    @Autowired
    private lateinit var tBcDailyLoanBillRepo: TBcDailyLoanBillRepo

    //借款单费用类型
    @Autowired
    private lateinit var tBcOperatorTypeRepo: TBcOperatorTypeRepo

    @Autowired
    private lateinit var tOrgBaseUnitRepo: TOrgBaseUnitRepo

    @Autowired
    private lateinit var encryptUtils: EncryptUtils

    @Autowired
    private lateinit var tBdSettlementTypeRepo: TBdSettlementTypeRepo

    @Autowired
    private lateinit var tBdBankRepo: TBdBankRepo

    @Autowired
    private lateinit var tBdAccountBankRepo: TBdAccountBankRepo

    @Autowired
    private lateinit var budgetDBRepo: BudgetDBRepo

    @Autowired
    private lateinit var receivingSummaryRepo: ReceivingSummaryRepo

    //付款单一级明细表
    @Autowired
    private lateinit var paymentFirstDetailRepo: PaymentFirstDetailRepo

    //付款单二级明细表
    @Autowired
    lateinit var paymentSecondDetailRepo: PaymentSecondDetailRepo

    //收支汇总
    @Autowired
    private lateinit var incomeExpenseSummaryRepo: IncomeExpenseSummaryRepo

    @Value("\${custom.precise-digit}")
    val preciseDigit: Int = 0

    /**
     * 获取所有的费用类型
     */
    fun getAllExpenseType(): List<TBcExpenseType> {
        val listNumber =
                listOf("yc001", "sd003", "sd002", "tr001", "hb001", "ww001", "ys001", "jl001", "cp001", "qt034", "fl001", "qt035", "GD001", "WX001", "zjgc001")
        return tBcExpenseTypeRepo.findAll(TBcExpenseType::fNumber.`in`(listNumber)).toList()
    }

    /**
     * 获取所有收款类型
     */
    fun getAllReceivingTypeName(type: TCasReceivingBillType): String {
        val listNumber = listOf("122", "123", "124", "125", "11111", "1112")
        tCasReceivingBillTypeRepo.findAll(TCasReceivingBillType::fNumber.`in`(listNumber))
        return when (type.fNumber) {
            "122" -> "主营业务收入"
            "123" -> "收处置废旧物资款"
            "124" -> "融资现金流入"
            "11111" -> "投资现金流入"
            "1112" -> "收集团内部公司转款"
            else -> "收其它款项"
        }
    }


    data class ReceivingKey(
            val name: String? = null,
            val data: Date? = null,
            val orgName: String? = null,
            val payMethod: String? = null
    )

    /**
     * 获取收款单每个月的每日收款总额
     */

    fun getMonthReceivingList(startTime: Date?, endTime: Date?): List<ReceivingEntity> {
        if (startTime != null && endTime != null) {
            val startCalendar = Calendar.getInstance()
            startCalendar.set(Calendar.DAY_OF_MONTH, 1)
            val endCalendar = Calendar.getInstance()
            endCalendar.set(Calendar.DAY_OF_MONTH, endCalendar.getActualMaximum(Calendar.DAY_OF_MONTH))
            startCalendar.time = startTime
            val startYear = startCalendar.get(Calendar.YEAR)
            val startMonth = startCalendar.get(Calendar.MONTH)
            endCalendar.time = endTime
            val endYear = endCalendar.get(Calendar.YEAR)
            val endMonth = endCalendar.get(Calendar.MONTH)
            val deleteList = receivingSummaryRepo.findAll(
                    ReceivingSummary::date.between(startCalendar.time, endCalendar.time))
            receivingSummaryRepo.deleteAll(deleteList)
            val allReceivingList = ArrayList<ReceivingEntity>()
            if (startYear != endYear) {//跨年同步 eg:2016-10-01 至 2018-05-10

                (startYear..endYear).forEach { year ->

                    val monthInfo = when (year) {
                        startYear -> mapOf("start" to startMonth, "end" to 12)
                        endYear -> mapOf("start" to 1, "end" to endMonth)
                        else -> mapOf("start" to 1, "end" to 12)
                    }
                    val start = monthInfo["start"]!!
                    val end = monthInfo["end"]!!
                    allReceivingList.addAll(getMonthReceivingAllData(start, end, year))
                }
            } else {
                allReceivingList.addAll(getMonthReceivingAllData(startMonth, endMonth, endYear))
            }
            return allReceivingList
        } else {
            val calendar = Calendar.getInstance()
            calendar.time = Date()
            val deleteList = receivingSummaryRepo.findAll(
                    ReceivingSummary::permitYear.equal(calendar.get(Calendar.YEAR)))
            receivingSummaryRepo.deleteAll(deleteList)
            return getMonthReceivingAllData(0, 11, calendar.get(Calendar.YEAR))
        }
    }

    fun getMonthReceivingAllData(start: Int, end: Int, year: Int): List<ReceivingEntity> {
        val allReceivingList = ArrayList<ReceivingEntity>()

        (start..end).forEach {
            val monthReceivingList = getReceivingDailyDetail(it, year)
            val sumList = monthReceivingList.filter { it.date != null }.filter { it.expenseName != null }
                    .sumBy(keySelector = { ReceivingKey(it.expenseName, it.date, it.orgName, it.payMethod) },
                            doubleSelector = { it.amount!!.toDouble() })
                    .map {
                        ReceivingEntity(encryptUtils.uuid(), null, it.key.name, it.value.toBigDecimal().setScale(preciseDigit, RoundingMode.HALF_UP),
                                it.key.orgName, it.key.data, null, it.key.payMethod,
                                null, null)
                    }
            val groupList = sumList.sumBy(keySelector = { ReceivingKey(it.expenseName, it.date, null, it.payMethod) },
                    doubleSelector = { it.amount!!.toDouble() })
                    .map {
                        ReceivingEntity(encryptUtils.uuid(), null, it.key.name, it.value.toBigDecimal().setScale(preciseDigit, RoundingMode.HALF_UP), "集团总部", it.key.data, null, it.key.payMethod, null)
                    }
            allReceivingList.addAll(sumList)
            allReceivingList.addAll(groupList)
        }
        return allReceivingList
    }


    /**
     * 获取本年的每个月所有的收款单数据
     */
    fun getAllMonthReceivingData(): List<ReceivingEntity> {
        val allReceivingList = ArrayList<ReceivingEntity>()
        (0..11).forEach {
            val monthReceivingList = getReceivingDailyDetail(it, 2018)

            allReceivingList.addAll(monthReceivingList)
        }
        return allReceivingList
    }

    /**
     * 获取收款单某个月内的每日收款记录
     *
     */
    fun getReceivingDailyDetail(firstMonth: Int, year: Int): List<ReceivingEntity> {
        val calendar = Calendar.getInstance()
        calendar.set(Calendar.YEAR, year)
        calendar.set(Calendar.MONTH, firstMonth)
        calendar.set(Calendar.DAY_OF_MONTH, 1)
        val firstDate = calendar.time

        calendar.set(Calendar.DAY_OF_MONTH, calendar.getActualMaximum(Calendar.DAY_OF_MONTH))
//        calendar.set(Calendar.DAY_OF_MONTH, 2)
        val lastDate = calendar.time
        val dateFormat = SimpleDateFormat("yyyy-MM-dd 00:00:00")
        val firstStr = dateFormat.format(firstDate)
        val lastStr = dateFormat.format(lastDate)
        val first = Timestamp.valueOf(firstStr)
//        println("firstDate-----------$first")
        val last = Timestamp.valueOf(lastStr)
//        println("lastDate-----------$last")
        val receivingType = tCasReceivingBillTypeRepo.findAll().toList()

        val spec = TCasReceivingBill::fBizDate.between(first, last) and TCasReceivingBill::fRecBillTypeId.`in`(receivingType.map { it.fid!! }) and TCasReceivingBill::fBillStatus.equal("12")
        val count = tCasReceivingBillRepo.count(spec)
        val receivingBillList = (0..count step 2000)
                .map { PageRequest.of(it.toInt() / 2000, 2000) }
                .map { tCasReceivingBillRepo.findAll(spec, it) }
                .flatten()


        //支付银行
        val bankList = tBdBankRepo.findAll(
                TBdBank::fid.`in`(
                        receivingBillList.filter { it.fPayeeBankId != null }.map { it.fPayeeBankId!! }.toSet()))
                .toList()
        //支付方式
        val payMethodList = tBdSettlementTypeRepo.findAll(
                TBdSettlementType::fid.`in`(
                        receivingBillList.filter { it.fSettlementTypeId != null }
                                .map { it.fSettlementTypeId!! }.toSet()))
                .toList()
        //银行账号
//        val bankAccount = tBdAccountBankRepo.findAll(
//                TBdAccountBanks::fid.`in`(
//                        receivingBillList.filter { it.fPayerAccountBankId != null }
//                                .map { it.fPayerAccountBankId!! }.toSet()))
//                .toList()
        val bankAccount = tBdAccountBankRepo.findAll()

        return if (receivingBillList.isNotEmpty()) {
            val baseUnitIds = receivingBillList.filter { it.fControlUnitId != null }
                    .map { it.fControlUnitId!! }.toList()
            val baseUnitList = tOrgBaseUnitRepo
                    .findAll(TOrgBaseUnit::fid.`in`(baseUnitIds)).toList()

            receivingBillList.filter { it.fRecBillTypeId != null }.map { entry ->
                val typeId = entry.fRecBillTypeId
                val controlUnitId = entry.fControlUnitId
                val orgUnit = baseUnitList.first { it.fid == controlUnitId }
                val typeInfo = receivingType.find { it.fid == typeId }
                val name = getAllReceivingTypeName(typeInfo!!)
                val payMethodName = payMethodList.find { it.fid == entry.fSettlementTypeId }?.fnameL2


                val payMethod = when (payMethodName) {
                    "电汇" -> "电汇"
                    "现金（有票）", "现金支票", "现金（无票）" -> "现金"
                    "应收票据(银行承兑汇票)", "银行承兑汇票", "商业承兑汇票" -> "承兑"
                    "普通支票", "转账支票" -> "支票"
                    else -> "其他"
                }

                val paymentType = when (payMethodName) {
                    "电汇" -> PaymentType.TELEGRAM
                    "现金（有票）", "现金支票", "现金（无票）" -> PaymentType.CASHES
                    "应收票据(银行承兑汇票)", "银行承兑汇票", "商业承兑汇票" -> PaymentType.ACCEPTANCE
                    "普通支票", "转账支票" -> PaymentType.CHECKS
                    else -> PaymentType.OTHERS
                }

                val bankAccounts = bankAccount.find { it.fid == entry.fPayeeAccountBankId }

                ReceivingEntity(encryptUtils.uuid(), typeId, name, entry.fActRecAmt,
                        orgUnit.fnameL2, entry.fBizDate, paymentType, payMethod,
                        bankList.find { it.fid == entry.fPayeeBankId }?.fnameL2,
                        bankAccounts?.fbankaccountnumber)
            }
        } else {
            ArrayList()
        }
    }


    data class PaymentSumKey(
            val date: Date? = null,
            val expenseName: String? = null,
            val orgName: String? = null,
            val paymentType: PaymentType? = null
    )

    data class PaymentGroupKey(
            val date: Date? = null,
            val expenseName: String? = null,
            val orgName: String? = null,
            val payMethod: String? = null
    )

    /**
     * 对付款单数据进行每日数据详情汇总
     * 即支出二级明细表
     */

    fun getAllPaymentSumData(startTime: Date?, endTime: Date?): List<PaymentEntity> {
        if (startTime != null && endTime != null) {
            val startCalendar = Calendar.getInstance()
            startCalendar.set(Calendar.DAY_OF_MONTH, 1)
            val endCalendar = Calendar.getInstance()
            endCalendar.set(Calendar.DAY_OF_MONTH, endCalendar.getActualMaximum(Calendar.DAY_OF_MONTH))
            startCalendar.time = startTime
            val startYear = startCalendar.get(Calendar.YEAR)
            val startMonth = startCalendar.get(Calendar.MONTH)
            endCalendar.time = endTime
            val endYear = endCalendar.get(Calendar.YEAR)
            val endMonth = endCalendar.get(Calendar.MONTH)

            val deleteList = paymentSecondDetailRepo.findAll(
                    PaymentSecondDetail::date.between(startCalendar.time, endCalendar.time))
            paymentSecondDetailRepo.deleteAll(deleteList)

            val paymentList = ArrayList<PaymentEntity>()
            if (startYear != endYear) {//跨年同步 eg:2016-10-01 至 2018-05-10
                (startYear..endYear).forEach { year ->

                    val monthInfo = when (year) {
                        startYear -> mapOf("start" to startMonth, "end" to 12)
                        endYear -> mapOf("start" to 1, "end" to endMonth)
                        else -> mapOf("start" to 1, "end" to 12)
                    }
                    val start = monthInfo["start"]!!
                    val end = monthInfo["end"]!!
                    paymentList.addAll(getAllPaymentSumDetailData(start, end, year))
                }
            } else {
                paymentList.addAll(getAllPaymentSumDetailData(startMonth, endMonth, endYear))
            }
            return paymentList
        } else {

            val calendar = Calendar.getInstance()
            calendar.time = Date()
            val deleteList = paymentSecondDetailRepo.findAll(
                    PaymentSecondDetail::permitYear.equal(calendar.get(Calendar.YEAR)))
            paymentSecondDetailRepo.deleteAll(deleteList)
            return getAllPaymentSumDetailData(0, 11, calendar.get(Calendar.YEAR))
        }
    }

    fun getAllPaymentSumDetailData(start: Int, end: Int, year: Int): List<PaymentEntity> {
        val allPaymentList = ArrayList<PaymentEntity>()

        (start..end).forEach {
            val paymentBillList = getAllPaymentBill(it, year)
            val paymentSumDataList = paymentBillList
                    .sumBy(keySelector = { PaymentSumKey(it.date, it.expenseName, it.orgName, it.dataSource) },
                            doubleSelector = { it.amount!!.toDouble() })
                    .map {
                        val payMethod = when (it.key.paymentType) {
                            PaymentType.ACCEPTANCE -> "承兑"
                            PaymentType.CASHES -> "现金"
                            PaymentType.CHECKS -> "支票"
                            PaymentType.TELEGRAM -> "电汇"
                            else -> "其他"
                        }
                        PaymentEntity(encryptUtils.uuid(), null, null, it.key.expenseName,
                                it.value.toBigDecimal().setScale(preciseDigit, RoundingMode.HALF_UP), it.key.date, it.key.orgName, null,
                                payMethod, null, null)
                    }
            val groupPaymentList = paymentSumDataList
                    .sumBy(keySelector = { PaymentGroupKey(it.date, it.expenseName, null, it.payMethod) },
                            doubleSelector = { it.amount!!.toDouble() })
                    .map {
                        PaymentEntity(encryptUtils.uuid(), null, null, it.key.expenseName,
                                it.value.toBigDecimal().setScale(preciseDigit, RoundingMode.HALF_UP), it.key.date,
                                "集团总部", null, it.key.payMethod,
                                null, null)
                    }
            allPaymentList.addAll(paymentSumDataList)
            allPaymentList.addAll(groupPaymentList)
        }
        return allPaymentList
    }

    /**
     * 对付款单中的大类型数据进行数据汇总
     * 即支出一级明细表
     */
    fun getAllTypePaymentSum(startTime: Date?, endTime: Date?): List<PaymentEntity> {
        if (startTime != null && endTime != null) {
            val startCalendar = Calendar.getInstance()
            startCalendar.set(Calendar.DAY_OF_MONTH, 1)
            val endCalendar = Calendar.getInstance()
            endCalendar.set(Calendar.DAY_OF_MONTH, endCalendar.getActualMaximum(Calendar.DAY_OF_MONTH))
            startCalendar.time = startTime
            val startYear = startCalendar.get(Calendar.YEAR)
            val startMonth = startCalendar.get(Calendar.MONTH)
            endCalendar.time = endTime
            val endYear = endCalendar.get(Calendar.YEAR)
            val endMonth = endCalendar.get(Calendar.MONTH)

            val deleteList = paymentFirstDetailRepo.findAll(
                    PaymentFirstDetail::date.between(startCalendar.time, endCalendar.time))
            paymentFirstDetailRepo.deleteAll(deleteList)

            val paymentList = ArrayList<PaymentEntity>()
            if (startYear != endYear) {//跨年同步 eg:2016-10-01 至 2018-05-10
                (startYear..endYear).forEach { year ->

                    val monthInfo = when (year) {
                        startYear -> mapOf("start" to startMonth, "end" to 12)
                        endYear -> mapOf("start" to 1, "end" to endMonth)
                        else -> mapOf("start" to 1, "end" to 12)
                    }
                    val start = monthInfo["start"]!!
                    val end = monthInfo["end"]!!
                    paymentList.addAll(getAllPaymentList(start, end, year))
                }
            } else {
                paymentList.addAll(getAllPaymentList(startMonth, endMonth, endYear))
            }
            return paymentList
        } else {

            val calendar = Calendar.getInstance()
            calendar.time = Date()
            val deleteList = paymentFirstDetailRepo.findAll(
                    PaymentFirstDetail::permitYear.equal(calendar.get(Calendar.YEAR)))
            paymentFirstDetailRepo.deleteAll(deleteList)
            return getAllPaymentList(0, 11, calendar.get(Calendar.YEAR))
        }
        /*val allPaymentList = ArrayList<PaymentEntity>()

        (0..11).forEach {
            val paymentList = getAllPaymentBill(it)
            val typePaymentList = getTypeAmount(paymentList)
            val sumAllPaymentList = typePaymentList
                    .sumBy(keySelector = { PaymentSumKey(it.date, it.expenseName, it.orgName, it.dataSource) }, doubleSelector = { it.amount!!.toDouble() })
                    .map {
                        val payMethod = when (it.key.paymentType) {
                            PaymentType.ACCEPTANCE -> "承兑"
                            PaymentType.CASHES -> "现金"
                            PaymentType.CHECKS -> "支票"
                            PaymentType.TELEGRAM -> "电汇"
                            else -> "其他"
                        }
                        PaymentEntity(encryptUtils.uuid(), null, null, it.key.expenseName, it.value.toBigDecimal().setScale(preciseDigit, RoundingMode.HALF_UP), it.key.date, it.key.orgName, null, payMethod, null, null)
                    }
            val groupSumList = sumAllPaymentList
                    .sumBy(keySelector = { PaymentGroupKey(it.date, it.expenseName, null, it.payMethod) }, doubleSelector = { it.amount!!.toDouble() })
                    .map {
                        PaymentEntity(encryptUtils.uuid(), null, null, it.key.expenseName, it.value.toBigDecimal().setScale(preciseDigit, RoundingMode.HALF_UP), it.key.date, "集团总部", null, it.key.payMethod, null, null)
                    }
            allPaymentList.addAll(sumAllPaymentList)
            allPaymentList.addAll(groupSumList)
        }
        return allPaymentList*/
    }

    fun getAllPaymentList(start: Int, end: Int, year: Int): List<PaymentEntity> {
        val allPaymentList = ArrayList<PaymentEntity>()

        (start..end).forEach {
            val paymentList = getAllPaymentBill(it, year)
            val typePaymentList = getTypeAmount(paymentList)
            val sumAllPaymentList = typePaymentList
                    .sumBy(keySelector = { PaymentSumKey(it.date, it.expenseName, it.orgName, it.dataSource) }, doubleSelector = { it.amount!!.toDouble() })
                    .map {
                        val payMethod = when (it.key.paymentType) {
                            PaymentType.ACCEPTANCE -> "承兑"
                            PaymentType.CASHES -> "现金"
                            PaymentType.CHECKS -> "支票"
                            PaymentType.TELEGRAM -> "电汇"
                            else -> "其他"
                        }
                        PaymentEntity(encryptUtils.uuid(), null, null, it.key.expenseName, it.value.toBigDecimal().setScale(preciseDigit, RoundingMode.HALF_UP), it.key.date, it.key.orgName, null, payMethod, null, null)
                    }
            val groupSumList = sumAllPaymentList
                    .sumBy(keySelector = { PaymentGroupKey(it.date, it.expenseName, null, it.payMethod) }, doubleSelector = { it.amount!!.toDouble() })
                    .map {
                        PaymentEntity(encryptUtils.uuid(), null, null, it.key.expenseName, it.value.toBigDecimal().setScale(preciseDigit, RoundingMode.HALF_UP), it.key.date, "集团总部", null, it.key.payMethod, null, null)
                    }
            allPaymentList.addAll(sumAllPaymentList)
            allPaymentList.addAll(groupSumList)
        }
        return allPaymentList
    }

    /**
     * 对付款单数据进行分月查询，最后进行所有数据的聚合
     */
    fun getAllMonthPayment() = (0..11).map {
        getAllPaymentBill(it, 2018)
    }
            .filter { it.isNotEmpty() }
            .map {

                it + getTypeAmount(it)
            }.flatten().sortedBy { it.date }

    /**
     * 获取付款单某个月对应的每日日报信息
     */
    fun getAllPaymentBill(firstMonth: Int, year: Int): List<PaymentEntity> {
        val calendar = Calendar.getInstance()
        calendar.set(Calendar.YEAR, year)
        calendar.set(Calendar.MONTH, firstMonth)
        calendar.set(Calendar.DAY_OF_MONTH, calendar.getActualMinimum(Calendar.DAY_OF_MONTH))
//        calendar.set(Calendar.DAY_OF_MONTH, 16)
        val firstDate = calendar.time

        calendar.set(Calendar.DAY_OF_MONTH, calendar.getActualMaximum(Calendar.DAY_OF_MONTH))
//        calendar.set(Calendar.DAY_OF_MONTH, 16)
        val lastDate = calendar.time
        val dateFormat = SimpleDateFormat("yyyy-MM-dd 00:00:00")
        val firstStr = dateFormat.format(firstDate)
        val lastStr = dateFormat.format(lastDate)
        val first = Timestamp.valueOf(firstStr)
//        println("firstDate-----------$first")
        val last = Timestamp.valueOf(lastStr)
//        println("lastDate-----------$last")
        val spec = TCasPaymentBill::fBizDate.between(first, last)and TCasPaymentBill ::fBillStatus.equal("15")
        val count = tCasPaymentBillRepo.count(spec)
        val payments = (0..count step 2000)
                .map { PageRequest.of(it.toInt() / 2000, 2000) }
                .map { tCasPaymentBillRepo.findAll(spec, it) }
                .flatten()
        return if (payments.isNotEmpty()) {
            val paymentIds = payments.map { it.fid!! }.toSet()
            val unitIds = payments.map { it.fControlUnitId!! }.toSet()
            val baseUnitList = tOrgBaseUnitRepo
                    .findAll(TOrgBaseUnit::fid.`in`(unitIds)).toList()
            val bankIds = payments.filter { it.fPayerBankId != null }
                    .map { it.fPayerBankId!! }.toSet()
            //支付银行
            val bankList = tBdBankRepo.findAll(TBdBank::fid.`in`(bankIds))
            //支付方式
            val payMethodList = tBdSettlementTypeRepo.findAll(
                    TBdSettlementType::fid.`in`(
                            payments.filter { it.fSettlementTypeId != null }.map { it.fSettlementTypeId!! }.toSet()))
                    .toList()
            //银行账号
            val bankAccount = tBdAccountBankRepo.findAll(
                    TBdAccountBanks::fid.`in`(
                            payments.filter { it.fPayerAccountBankId != null }
                                    .map { it.fPayerAccountBankId!! }.toSet()))
                    .toList()

            val subPayments = tCasPaymentBillEntryRepo
                    .findAll(TCasPaymentBillEntry::fPaymentBillId.`in`(paymentIds))
            subPayments.filter { it.fExpenseTypeId != null }.map { entry ->
                val payment = payments.first { it.fid == entry.fPaymentBillId }
                val baseUnit = baseUnitList.first { it.fid == payment.fControlUnitId }
                val type = getAllExpenseType().find { entry.fExpenseTypeId == it.fid }
                val payMethodEntity =
                        payMethodList.firstOrNull { it.fid == payment.fSettlementTypeId }
                val bankInfo = bankList.firstOrNull { it.fid == payment.fPayerBankId }
                val accountInfo = bankAccount.firstOrNull { it.fid == payment.fPayerAccountBankId }

                val paymentMethod = when (payMethodEntity?.fnameL2) {
                    "电汇" -> "电汇"
                    "现金（有票）", "现金（无票）" -> "现金"
                    "应收票据(银行承兑汇票)", "银行承兑汇票", "商业承兑汇票" -> "承兑"
                    "普通支票", "转账支票", "现金支票" -> "支票"
                    else -> "其他"
                }

                val paymentType = when (payMethodEntity?.fnameL2) {
                    "电汇" -> PaymentType.TELEGRAM
                    "现金（有票）", "现金（无票）" -> PaymentType.CASHES
                    "应收票据(银行承兑汇票)", "银行承兑汇票", "商业承兑汇票" -> PaymentType.ACCEPTANCE
                    "普通支票", "转账支票", "现金支票" -> PaymentType.CHECKS
                    else -> PaymentType.OTHERS
                }

                PaymentEntity(
                        entry.fid!!, sortExpense(type), entry.fExpenseTypeId, type?.fNameL2, entry.fActualAmt
                        , Date(payments.find { it.fid == entry.fPaymentBillId }?.fBizDate?.time!!),
                        baseUnit.fnameL2, paymentType, paymentMethod,
                        bankInfo?.fnameL2, accountInfo?.fbankaccountnumber)
            }
        } else {
            ArrayList()
        }
    }

    data class Key(
            val orgName: String? = null,
            val payMethod: String? = null,
            val date: Date? = null,
            val dailyType: DailyType? = null
    )

    fun getTypeAmount(paymentList: List<PaymentEntity>) =
            paymentList.filter { it.date != null }.filter { it.payMethod != null }
                    .sumBy(keySelector = { Key(it.orgName, it.payMethod, it.date, it.dailyType) },
                            doubleSelector = { it.amount!!.toDouble() })
                    .map {
                        val payMethod = when (it.key.payMethod) {
                            "电汇" -> PaymentType.TELEGRAM
                            "现金" -> PaymentType.CASHES
                            "承兑" -> PaymentType.ACCEPTANCE
                            "支票" -> PaymentType.CHECKS
                            else -> PaymentType.OTHERS
                        }

                        PaymentEntity(encryptUtils.uuid(), it.key.dailyType, null,
                                when (it.key.dailyType) {
                                    DailyType.OPERATOR -> "经营性资金流出"
                                    DailyType.FINANCING -> "筹资活动资金流出"
                                    DailyType.INVEST -> "投资活动资金流出"
                                    DailyType.OTHER -> "其他资金流出"
                                    else -> "其他"
                                }, it.value.toBigDecimal().setScale(preciseDigit, RoundingMode.HALF_UP), it.key.date, it.key.orgName, payMethod, it.key.payMethod)
                    }


//    //付款单信息聚合数据集
    /*fun getTypeAmount(paymentList: List<PaymentEntity>): List<PaymentEntity> {
        val billList = paymentList.filter { it.date != null }


        val orgNameList = paymentList.filter { it.orgName != null }.map { it.orgName }.toSet()
        val dateList = billList.map { it.date }.toSet()
        val payMethodList = billList.map { it.payMethod }.toSet()

        billList.sumBy(keySelector = { Key(it.orgName, it.payMethod, it.date, it.dailyType) }, doubleSelector = { it.amount!!.toDouble() })

        val totalList = ArrayList<PaymentEntity>()
        for (date in dateList) {
            for (orgName in orgNameList) {
                val tempList =
                        paymentList.filter { it.date == date }.filter { it.orgName == orgName }.toList()
                println("----temp---------------")
                println(tempList)
                println(tempList.size)
                println("----temp---------------")
                val entityList = paymentList
                        .filter { it.date == date }
                        .filter { it.orgName == orgName }
                        .groupBy { it.dailyType }
                        .map {
                            val dailyType = it.key
                            val name = when (dailyType) {
                                DailyType.OPERATOR -> "经营性资金流出"
                                DailyType.FINANCING -> "筹资活动资金流出"
                                DailyType.INVEST -> "投资活动资金流出"
                                else -> "其他资金流出"
                            }
                            val amount = it.value.map { it.amount!! }.reduce(BigDecimal::add)
                            PaymentEntity("", dailyType, null, name, amount, date,
                                    orgName, DataSource.INDIRECT)
                        }
                println("entityList----$entityList")
                totalList.addAll(entityList)
            }
        }
        return totalList
    }*/

    private fun sortExpense(expenseType: TBcExpenseType?): DailyType {
        val expenseNumber = expenseType?.fNumber
        return when (expenseNumber) {
            //经营性资金流出
            "yc001", "sd003", "sd002", "tr001", "hb001",
            "ww001", "ys001", "jl001", "cp001", "cp002",
            "qt034", "fl001", "qt035" -> DailyType.OPERATOR
            //筹资活动资金流出
//            "" -> DailyType.FINANCING
            //投资活动资金流出
            "GD001", "WX001", "zjgc001" -> DailyType.INVEST
            //其他资金流出
            else -> DailyType.OTHER
        }
    }


    data class FundKey(
            val orgName: String? = null,
            val date: Date? = null,
            val payMethod: PaymentType? = null
    )

    data class FundSumKey(
            val date: Date? = null,
            val payMethod: String? = null
    )

    fun getDateYear(startTime: Date, endTime: Date) {
        val startCalendar = Calendar.getInstance()
        val endCalendar = Calendar.getInstance()
        startCalendar.time = startTime
        endCalendar.time = endTime
        startCalendar.set(Calendar.DAY_OF_MONTH, endCalendar.getActualMaximum(Calendar.DAY_OF_MONTH))
        println(startTime)
        println(startCalendar.time)

        if (startTime == startCalendar.time) {
            println("true")
        } else {
            println("false")
        }


    }

    /**
     * 获取收支汇总数据源
     */
    fun getFundSummaryData(startTime: Date?, endTime: Date?): List<FundSummary> {
        if (startTime != null && endTime != null) {
            val startCalendar = Calendar.getInstance()
            startCalendar.set(Calendar.DAY_OF_MONTH, 1)
            val endCalendar = Calendar.getInstance()
            endCalendar.set(Calendar.DAY_OF_MONTH, endCalendar.getActualMaximum(Calendar.DAY_OF_MONTH))
            startCalendar.time = startTime
            val startYear = startCalendar.get(Calendar.YEAR)
            val startMonth = startCalendar.get(Calendar.MONTH)
            endCalendar.time = endTime
            val endYear = endCalendar.get(Calendar.YEAR)
            val endMonth = endCalendar.get(Calendar.MONTH)

            val deleteList = incomeExpenseSummaryRepo.findAll(
                    IncomeExpenseSummary::date.between(startCalendar.time, endCalendar.time))
            incomeExpenseSummaryRepo.deleteAll(deleteList)

            val summaryList = ArrayList<FundSummary>()
            if (startYear != endYear) {//跨年同步 eg:2016-10-01 至 2018-05-10
                (startYear..endYear).forEach { year ->

                    val monthInfo = when (year) {
                        startYear -> mapOf("start" to startMonth, "end" to 12)
                        endYear -> mapOf("start" to 1, "end" to endMonth)
                        else -> mapOf("start" to 1, "end" to 12)
                    }
                    val start = monthInfo["start"]!!
                    val end = monthInfo["end"]!!
                    summaryList.addAll(getSummaryList(start, end, year))
                }
            } else {
                summaryList.addAll(getSummaryList(startMonth, endMonth, endYear))
            }
            return summaryList
        } else {
            val calendar = Calendar.getInstance()
            calendar.time = Date()
            val nowYear = calendar.get(Calendar.YEAR)
            val deleteList = incomeExpenseSummaryRepo.findAll(
                    IncomeExpenseSummary::permitYear.equal(nowYear))
            incomeExpenseSummaryRepo.deleteAll(deleteList)
            return getSummaryList(0, 11, nowYear)
        }

        /*val summaryList = ArrayList<FundSummary>()
        (0..11).forEach {
            val allPaymentList = getAllPaymentBill(it)
            val paymentList = allPaymentList
                    .sumBy(keySelector = { FundKey(it.orgName, it.date, it.dataSource) }, doubleSelector = { it.amount!!.toDouble() })
                    .map {
                        val payName = when (it.key.payMethod) {
                            PaymentType.TELEGRAM -> "电汇总额"
                            PaymentType.CASHES -> "现金总额"
                            PaymentType.ACCEPTANCE -> "承兑总额"
                            PaymentType.CHECKS -> "支票总额"
                            else -> "其他总额"
                        }
                        FundSummary(it.key.orgName, it.key.date, FundType.PAYMENT,
                                payName, it.value.toBigDecimal().setScale(preciseDigit, RoundingMode.HALF_UP))
                    }
            val sumPaymentList = paymentList
                    .sumBy(keySelector = { FundSumKey(it.date, it.payName) },
                            doubleSelector = { it.payAccount!!.toDouble() })
                    .map {
                        FundSummary("集团总部", it.key.date, FundType.PAYMENT, it.key.payMethod,
                                it.value.toBigDecimal().setScale(preciseDigit, RoundingMode.HALF_UP))
                    }
            summaryList.addAll(paymentList)
            summaryList.addAll(sumPaymentList)
            val allReceivingList = getReceivingDailyDetail(it)
            val receivingList = allReceivingList
                    .sumBy(keySelector = { FundKey(it.orgName, it.date, it.payType) },
                            doubleSelector = { it.amount!!.toDouble() })
                    .map {
                        val payName = when (it.key.payMethod) {
                            PaymentType.TELEGRAM -> "电汇总额"
                            PaymentType.CASHES -> "现金总额"
                            PaymentType.ACCEPTANCE -> "承兑总额"
                            PaymentType.CHECKS -> "支票总额"
                            else -> "其他总额"
                        }
                        FundSummary(it.key.orgName, it.key.date, FundType.RECEIVING, payName,
                                it.value.toBigDecimal().setScale(preciseDigit, RoundingMode.HALF_UP))

                    }
            val sumReceivingList = receivingList
                    .sumBy(keySelector = { FundSumKey(it.date, it.payName) },
                            doubleSelector = { it.payAccount!!.toDouble() })
                    .map {
                        FundSummary("集团总部", it.key.date, FundType.RECEIVING, it.key.payMethod,
                                it.value.toBigDecimal().setScale(preciseDigit, RoundingMode.HALF_UP))
                    }
            summaryList.addAll(receivingList)
            summaryList.addAll(sumReceivingList)
        }
        return summaryList*/
    }

    fun getSummaryList(start: Int, end: Int, year: Int): List<FundSummary> {
        val summaryList = ArrayList<FundSummary>()
        (0..11).forEach {
            val allPaymentList = getAllPaymentBill(it, year)
            val paymentList = allPaymentList
                    .sumBy(keySelector = { FundKey(it.orgName, it.date, it.dataSource) }, doubleSelector = { it.amount!!.toDouble() })
                    .map {
                        val payName = when (it.key.payMethod) {
                            PaymentType.TELEGRAM -> "电汇总额"
                            PaymentType.CASHES -> "现金总额"
                            PaymentType.ACCEPTANCE -> "承兑总额"
                            PaymentType.CHECKS -> "支票总额"
                            else -> "其他总额"
                        }
                        FundSummary(it.key.orgName, it.key.date, FundType.PAYMENT,
                                payName, it.value.toBigDecimal().setScale(preciseDigit, RoundingMode.HALF_UP))
                    }
            val sumPaymentList = paymentList
                    .sumBy(keySelector = { FundSumKey(it.date, it.payName) },
                            doubleSelector = { it.payAccount!!.toDouble() })
                    .map {
                        FundSummary("集团总部", it.key.date, FundType.PAYMENT, it.key.payMethod,
                                it.value.toBigDecimal().setScale(preciseDigit, RoundingMode.HALF_UP))
                    }
            summaryList.addAll(paymentList)
            summaryList.addAll(sumPaymentList)
            val allReceivingList = getReceivingDailyDetail(it, year)
            val receivingList = allReceivingList
                    .sumBy(keySelector = { FundKey(it.orgName, it.date, it.payType) },
                            doubleSelector = { it.amount!!.toDouble() })
                    .map {
                        val payName = when (it.key.payMethod) {
                            PaymentType.TELEGRAM -> "电汇总额"
                            PaymentType.CASHES -> "现金总额"
                            PaymentType.ACCEPTANCE -> "承兑总额"
                            PaymentType.CHECKS -> "支票总额"
                            else -> "其他总额"
                        }
                        FundSummary(it.key.orgName, it.key.date, FundType.RECEIVING, payName,
                                it.value.toBigDecimal().setScale(preciseDigit, RoundingMode.HALF_UP))

                    }
            val sumReceivingList = receivingList
                    .sumBy(keySelector = { FundSumKey(it.date, it.payName) },
                            doubleSelector = { it.payAccount!!.toDouble() })
                    .map {
                        FundSummary("集团总部", it.key.date, FundType.RECEIVING, it.key.payMethod,
                                it.value.toBigDecimal().setScale(preciseDigit, RoundingMode.HALF_UP))
                    }
            summaryList.addAll(receivingList)
            summaryList.addAll(sumReceivingList)
        }
        return summaryList
    }

    data class LoanKey(
            val orgName: String? = null,
            val date: Date? = null,
            val loanType: String? = null,
            val payMethod: String? = null
    )

    /**
     * 获取借款单数据源
     */
    fun getLoanData(month: Int, year: Int): List<LoanEntity> {
        val calendar = Calendar.getInstance()
        calendar.set(Calendar.YEAR, year)
        calendar.set(Calendar.MONTH, month)
        calendar.set(Calendar.DAY_OF_MONTH, calendar.getActualMinimum(Calendar.DAY_OF_MONTH))
//        calendar.set(Calendar.DAY_OF_MONTH, 16)
        val firstDate = calendar.time

        calendar.set(Calendar.DAY_OF_MONTH, calendar.getActualMaximum(Calendar.DAY_OF_MONTH))
//        calendar.set(Calendar.DAY_OF_MONTH, 16)
        val lastDate = calendar.time
        val dateFormat = SimpleDateFormat("yyyy-MM-dd 00:00:00")
        val firstStr = dateFormat.format(firstDate)
        val lastStr = dateFormat.format(lastDate)
        val first = Timestamp.valueOf(firstStr)
//        println("firstDate-----------$first")
        val last = Timestamp.valueOf(lastStr)
//        println("lastDate-----------$last")
        val spec = TBcDailyLoanBill::fauditdate.between(first, last) and TBcDailyLoanBill::fstate.equal(60)
        val count = tBcDailyLoanBillRepo.count(spec)
        val loanBillList = (0..count step 2000)
                .map { PageRequest.of(it.toInt() / 2000, 2000) }
                .map { tBcDailyLoanBillRepo.findAll(spec, it) }
                .flatten()
        val baseUnitList = tOrgBaseUnitRepo.findAll().toList()
        val operatorTypeList = tBcOperatorTypeRepo.findAll().toList()
        return if (loanBillList.isNotEmpty()) {
            return loanBillList.filter { it.fauditdate != null }
                    .filter { it.fcontrolunitid != null }
                    .filter { it.fpayment != null }
                    .sumBy(keySelector = { LoanKey(it.fcontrolunitid, it.fauditdate, it.fpayment, it.fpayment) },
                            doubleSelector = { it.famount!!.toDouble() })
                    .map {
                        val orgId = it.key.orgName
                        val paymentId = it.key.loanType
                        val baseUnit = baseUnitList.find { it.fid == orgId }
                        val operatorType = operatorTypeList.find { it.fid == paymentId }
                        LoanEntity(baseUnit?.fnameL2, it.key.date, operatorType?.fnameL2, it.value.toBigDecimal().setScale(preciseDigit, RoundingMode.HALF_UP))
                    }
        } else {
            ArrayList()
        }
    }

    fun getBudgetDataActual(startTime: Date?, endTime: Date?): List<LoanEntity> {
        if (startTime != null && endTime != null) {
            val startCalendar = Calendar.getInstance()
            val endCalendar = Calendar.getInstance()
            startCalendar.time = startTime
            val startYear = startCalendar.get(Calendar.YEAR)
            val startMonth = startCalendar.get(Calendar.MONTH)
            startCalendar.set(Calendar.DAY_OF_MONTH, 1)

            endCalendar.time = endTime
            val endYear = endCalendar.get(Calendar.YEAR)
            val endMonth = endCalendar.get(Calendar.MONTH)
            endCalendar.set(Calendar.DAY_OF_MONTH, endCalendar.getActualMaximum(Calendar.DAY_OF_MONTH))
            println(startCalendar.time)
            println(endCalendar.time)

            val deleteList = budgetDBRepo.findAll(BudgetDB::date.between(startCalendar.time, endCalendar.time))
            println("---------------delete---------------")
            println(deleteList.size)
            budgetDBRepo.deleteAll(deleteList)
            val budgetList = ArrayList<LoanEntity>()
            if (startYear != endYear) {//跨年同步 eg:2016-10-01 至 2018-05-10
                (startYear..endYear).forEach { year ->

                    val monthInfo = when (year) {
                        startYear -> mapOf("start" to startMonth, "end" to 12)
                        endYear -> mapOf("start" to 1, "end" to endMonth)
                        else -> mapOf("start" to 1, "end" to 12)
                    }
                    val start = monthInfo["start"]!!
                    val end = monthInfo["end"]!!
                    budgetList.addAll(getBudgetDatas(start, end, year))
                }
            } else {
                budgetList.addAll(getBudgetDatas(startMonth, endMonth, endYear))
            }
            println("---------------add---------------")
            println(budgetList.size)
            return budgetList
        } else {
            val calendar = Calendar.getInstance()
            calendar.time = Date()
            val deleteList = budgetDBRepo.findAll(
                    BudgetDB::permitYear.equal(calendar.get(Calendar.YEAR)))
            budgetDBRepo.deleteAll(deleteList)
            return getBudgetDatas(0, 11, calendar.get(Calendar.YEAR))
        }
    }

    fun getBudgetDatas(start: Int, end: Int, year: Int): List<LoanEntity> {

        val budgetList = ArrayList<LoanEntity>()
        val allPaymentList = getAllPaymentSumDetailData(start, end, year)
        val paymentList = allPaymentList.map {
            LoanEntity(it.orgName, it.date, it.expenseName, it.amount, it.payMethod)
        }
        val allLoanEntityList = ArrayList<LoanEntity>()
        (start..end).forEach {
            val loanList = getLoanData(it, year)
            allLoanEntityList.addAll(loanList)
        }

        budgetList.addAll(paymentList)
        budgetList.addAll(allLoanEntityList)

        val budgetSumList = ArrayList<LoanEntity>()
        val budgets = budgetList.sumBy(keySelector = { LoanKey(it.orgName, it.date, it.titleName, it.payMethod) },
                doubleSelector = { it.account!!.toDouble() })
                .map {
                    LoanEntity(it.key.orgName, it.key.date, it.key.loanType, it.value.toBigDecimal().setScale(preciseDigit, RoundingMode.HALF_UP), it.key.payMethod)
                }
        val sumBudgets = budgets.sumBy(keySelector = { LoanKey(null, it.date, it.titleName, it.payMethod) },
                doubleSelector = { it.account!!.toDouble() })
                .map {
                    LoanEntity("集团总部", it.key.date, it.key.loanType, it.value.toBigDecimal().setScale(preciseDigit, RoundingMode.HALF_UP), it.key.payMethod)
                }
        budgetSumList.addAll(budgets)
        budgetSumList.addAll(sumBudgets)

        return budgetSumList
    }
}